package main

// go连接mysql
import (
	"database/sql"
	"fmt"

	_ "github.com/go-sql-driver/mysql" // init()
)

var db *sql.DB                                                  // 是一个连接池
var dsn string = "root:root333@tcp(127.0.0.1:3306)/go_sql_test" // 数据库信息
type user struct {
	id   int
	name string
	age  uint
}

// 初始化数据库
func initDb() (err error) {
	// 连接数据库
	db, err = sql.Open("mysql", dsn)
	if err != nil {
		return
	}
	err = db.Ping()
	if err != nil {
		return
	}
	// 设置数据库连接池最大数目，默认为0，即不限制，超过连接数目，会产生阻塞
	db.SetMaxOpenConns(10)
	// 设置连接池中最大闲置连接数目（请求数据量较小时，会关闭部分连接池）
	db.SetMaxIdleConns(5)
	return nil
}

// 查询
func queryOne(id int) {
	var u user
	// 1. 写查询单条记录的sql语句
	sqlStr := "select id,name,age from user where id>?;"
	// 2. 执行
	// rowObj := db.QueryRow(sqlStr, 1) // 1 会替换 ?
	// 3. 拿到结果
	// rowObj.Scan(&u.id, &u.name, &u.age) // 必须对rowObj调用Scan方法，因为该方法会释放数据池连接
	db.QueryRow(sqlStr, id).Scan(&u.id, &u.name, &u.age)
	fmt.Printf("u: %v\n", u)
}

// 查询
func queryMore(id int) {
	// 1.sql
	sqlStr := "select id,name,age from user where id>?"
	// 2.执行
	rows, err := db.Query(sqlStr, id)
	if err != nil {
		fmt.Printf("err: %v\n", err)
		return
	}
	// 3. 一定要关闭连接
	defer rows.Close()
	// 4. 循环取值
	for rows.Next() {
		var u user
		err := rows.Scan(&u.id, &u.name, &u.age)
		if err != nil {
			fmt.Printf("err: %v\n", err)
			return
		}
		fmt.Printf("u: %v\n", u)
	}
}

// 插入数据
func insert(name string, age int) {
	sqlStr := fmt.Sprintf("insert into user(name,age) values(%#v,%d)", name, age)
	ret, err := db.Exec(sqlStr)
	if err != nil {
		fmt.Printf("insert failed, err: %v\n", err)
		return
	}
	// 插入数据，会拿到插入数据的id
	id, err := ret.LastInsertId()
	if err != nil {
		fmt.Printf("insert success,but get id failed, err: %v\n", err)
		return
	}
	fmt.Printf("insert success, it is id: %v\n", id)
}

// 更新数据
func updateRow(id int, name string, age int) {
	sqlStr := "update user set name=?,age=? where id=?"
	ret, err := db.Exec(sqlStr, name, age, id)
	if err != nil {
		fmt.Printf("update failed, err: %v\n", err)
		return
	}
	n, err := ret.RowsAffected()
	if err != nil {
		fmt.Printf("insert success,but get id failed, err: %v\n", err)
		return
	}
	fmt.Printf("更新了%v行数据\n", n)
}

// 删除
func removeRow(id int) {
	sqlStr := "delete from user where id=?"
	n, err := db.Exec(sqlStr, id)
	if err != nil {
		fmt.Printf("delete failed, err: %v\n", err)
		return
	}
	fmt.Printf("此次操作共删除了%v行数据\n", n)
}

// 使用预处理插入多条数据
func prepareInsert() {
	sqlStr := "insert into user(name,age) values(?,?)"
	stmt, err := db.Prepare(sqlStr)
	if err != nil {
		fmt.Printf("err: %v\n", err)
		return
	}
	defer stmt.Close()

	var p = make(map[string]int, 5)
	p["李梓荇"] = 20
	p["王冬冬"] = 31
	p["周建国"] = 53
	p["牛胜"] = 47
	for k, v := range p {
		stmt.Exec(k, v)
		fmt.Printf("k: %v,v: %v 插入成功\n", k, v)
	}
}

func main() {
	err := initDb()
	if err != nil {
		fmt.Printf("init DB failed, err: %v\n", err)
		return
	}
	fmt.Println("数据库连接成功")

	queryOne(2)
	fmt.Println("---------------")
	queryMore(0)

	// insert("jerry", 38)
	// updateRow(5, "小红", 18)
	// removeRow(6)

	// prepareInsert()
}
